package cards;

import game.theGame;
import java.io.PrintStream;
import java.util.*;

// Referenced classes of package cards:
//            card

public class hand
{

    public int playernumber;
    public List pairs;
    public List triples;
    public List fourOfAKind;
    public List threeStraight;
    public List fourStraight;
    public List fiveStraight;
    public List sixStraight;
    public List sevenStraight;
    public List eightStraight;
    public List nineStraight;
    public List tenStraight;
    public List elevenStraight;
    public List twelveStraight;
    public List thirteenStraight;
    int handvalue;
    public List theHand;
    private List listOfStraights;
    public List combList;

    public int cardsLeft()
    {
        return theHand.size();
    }

    public List twos()
    {
        List l = new ArrayList();
        for(Iterator iter = theHand.iterator(); iter.hasNext();)
        {
            card c = (card)iter.next();
            if(c.value == 12)
            {
                l.add(c);
            }
        }

        return l;
    }

    public boolean hasTwoHearts()
    {
        List l = twos();
        for(Iterator iter = l.iterator(); iter.hasNext();)
        {
            card c = (card)iter.next();
            if(c.suit.equals("Hearts"))
            {
                return true;
            }
        }

        return false;
    }

    public int getConsHV()
    {
        int handvalue0 = 0;
        card card1;
        for(Iterator iter = freeSingles().iterator(); iter.hasNext();)
        {
            card1 = (card)iter.next();
        }

        return handvalue0;
    }

    public int getHandValue(theGame game)
    {
        hand countingHand = new hand(game.countingcards(), -1);
        int mediancardvalue = game.medianCardValue().getValue();
        handvalue = 0;
        Iterator iter;
        for(iter = theHand.iterator(); iter.hasNext();)
        {
            int cardvalue = ((card)iter.next()).getValue();
            if(mediancardvalue >= cardvalue)
            {
                handvalue += -4;
            } else
            if(cardvalue == 12)
            {
                handvalue += 3;
            } else
            {
                handvalue += -3;
            }
        }

        getPairs();
        iter = pairs.iterator();
        List cp = countingHand.pairs;
        if(cp.size() > 0)
        {
            cp = (List)cp.get(cp.size() / 2);
            card tempcard = (card)cp.get(0);
            while(iter.hasNext()) 
            {
                int curPair = ((card)((List)iter.next()).get(0)).getValue();
                if(curPair > tempcard.getValue())
                {
                    handvalue++;
                } else
                {
                    handvalue--;
                }
            }
        }
        handvalue += triples.size() * 4;
        handvalue += fourStraight.size() * 4;
        handvalue += fiveStraight.size() * 5;
        if(sixStraight.size() > 0)
        {
            handvalue += sixStraight.size() * 7;
        }
        handvalue += fourOfAKind.size() * 7;
        iter = threeStraight.iterator();
        cp = countingHand.threeStraight;
        if(cp.size() > 0)
        {
            cp = (List)cp.get(cp.size() / 2);
            cp = (List)cp.get(0);
            card tempcard = (card)cp.get(0);
            while(iter.hasNext()) 
            {
                int curTS = ((card)((List)((List)iter.next()).get(0)).get(0)).getValue();
                if(curTS > tempcard.getValue())
                {
                    handvalue += -2;
                } else
                {
                    handvalue += 2;
                }
            }
        }
        handvalue += freeSingles().size() * -3;
        handvalue += straightExtra().size() * -2;
        return handvalue;
    }

    public void delHandFromHand(List l)
    {
        for(Iterator iter = l.iterator(); iter.hasNext(); deleteFromHand((card)iter.next())) { }
    }

    public void addHandToHand(List l)
    {
        for(Iterator iter = l.iterator(); iter.hasNext(); theHand.add(iter.next())) { }
        sortHand();
    }

    public void deleteFromHand(card c)
    {
        theHand.remove(c);
        for(Iterator iterP = pairs.iterator(); iterP.hasNext();)
        {
            List l = (List)iterP.next();
            if(l.contains(c))
            {
                pairs.remove(l);
                iterP = pairs.iterator();
            }
        }

        for(Iterator iterP = triples.iterator(); iterP.hasNext();)
        {
            List l = (List)iterP.next();
            if(l.contains(c))
            {
                triples.remove(l);
                iterP = triples.iterator();
            }
        }

        for(Iterator iterP = fourOfAKind.iterator(); iterP.hasNext();)
        {
            List l = (List)iterP.next();
            if(l.contains(c))
            {
                fourOfAKind.remove(l);
                break;
            }
        }

        removeFromStraight(c, threeStraight);
        checkEmpty(threeStraight);
        checkEmpty(fourStraight);
        checkEmpty(fiveStraight);
        checkEmpty(sixStraight);
        checkEmpty(sevenStraight);
        checkEmpty(eightStraight);
        checkEmpty(nineStraight);
        checkEmpty(tenStraight);
        checkEmpty(elevenStraight);
        checkEmpty(twelveStraight);
        checkEmpty(thirteenStraight);
    }

    private void removeFromStraight(card c, List straight)
    {
        for(Iterator iter = straight.iterator(); iter.hasNext();)
        {
            List subList = (List)iter.next();
            for(Iterator subIter = subList.iterator(); subIter.hasNext();)
            {
                List listOfCards = (List)subIter.next();
                if(listOfCards.contains(c))
                {
                    listOfCards.remove(c);
                    if(listOfCards.isEmpty())
                    {
                        straight.remove(subList);
                        iter = straight.iterator();
                    }
                }
            }

        }

    }

    private void checkEmpty(List straight)
    {
        for(Iterator iter = straight.iterator(); iter.hasNext();)
        {
            List subList = (List)iter.next();
            for(Iterator subIter = subList.iterator(); subIter.hasNext();)
            {
                List listOfCards = (List)subIter.next();
                if(listOfCards.isEmpty())
                {
                    straight.remove(subList);
                    iter = straight.iterator();
                }
            }

        }

    }

    public List twoAtRandom()
    {
        List l = new ArrayList();
        Random r = new Random();
        int a = r.nextInt(13);
        int b;
        for(b = r.nextInt(13); a == b; b = r.nextInt(13)) { }
        l.add(theHand.get(a));
        l.add(theHand.get(b));
        return l;
    }

    public hand(List hand, int pnum)
    {
        pairs = new ArrayList();
        triples = new ArrayList();
        fourOfAKind = new ArrayList();
        threeStraight = new ArrayList();
        fourStraight = new ArrayList();
        fiveStraight = new ArrayList();
        sixStraight = new ArrayList();
        sevenStraight = new ArrayList();
        eightStraight = new ArrayList();
        nineStraight = new ArrayList();
        tenStraight = new ArrayList();
        elevenStraight = new ArrayList();
        twelveStraight = new ArrayList();
        thirteenStraight = new ArrayList();
        listOfStraights = new ArrayList();
        combList = new ArrayList();
        theHand = hand;
        playernumber = pnum;
        sortHand();
        getPairs();
        getTriples();
        getFourKind();
        combList();
        getStraight(3, threeStraight);
        getStraight(4, fourStraight);
        getStraight(5, fiveStraight);
        getStraight(6, sixStraight);
        getStraight(7, sevenStraight);
        getStraight(8, eightStraight);
        getStraight(9, nineStraight);
        getStraight(10, tenStraight);
        getStraight(11, elevenStraight);
        getStraight(12, twelveStraight);
        getStraight(13, thirteenStraight);
        listOfStraights.add(threeStraight);
        listOfStraights.add(fourStraight);
        listOfStraights.add(fiveStraight);
        listOfStraights.add(sixStraight);
        listOfStraights.add(sevenStraight);
        listOfStraights.add(eightStraight);
        listOfStraights.add(nineStraight);
        listOfStraights.add(tenStraight);
        listOfStraights.add(elevenStraight);
        listOfStraights.add(twelveStraight);
        listOfStraights.add(thirteenStraight);
    }

    public void sortHand()
    {
        boolean changing = true;
        while(changing) 
        {
            changing = false;
            for(int i = 0; i < theHand.size() - 1; i++)
            {
                card c1 = (card)theHand.get(i);
                card c2 = (card)theHand.get(i + 1);
                if(c1.value > c2.value)
                {
                    card temp = c1;
                    c1 = c2;
                    c2 = temp;
                    changing = true;
                } else
                if(c1.value == c2.value)
                {
                    if(c1.suit.equals("Clubs") && c2.suit.equals("Spades"))
                    {
                        card temp = c1;
                        c1 = c2;
                        c2 = temp;
                        changing = true;
                    }
                    if(c1.suit.equals("Diamonds") && (c2.suit.equals("Clubs") || c2.suit.equals("Spades")))
                    {
                        card temp = c1;
                        c1 = c2;
                        c2 = temp;
                        changing = true;
                    }
                    if(c1.suit.equals("Hearts") && (c2.suit.equals("Clubs") || c2.suit.equals("Spades") || c2.suit.equals("Diamonds")))
                    {
                        card temp = c1;
                        c1 = c2;
                        c2 = temp;
                        changing = true;
                    }
                }
                theHand.remove(i);
                theHand.add(i, c1);
                theHand.remove(i + 1);
                theHand.add(i + 1, c2);
            }

        }
    }

    public void printHand()
    {
        int z = 0;
        for(Iterator cardIter = theHand.iterator(); cardIter.hasNext();)
        {
            card currentCard = (card)cardIter.next();
            System.out.print(currentCard);
            if(z >= 4)
            {
                z = 0;
                System.out.println();
            }
            z++;
        }

        System.out.println();
    }

    public boolean endGame()
    {
        return theHand.isEmpty();
    }

    private void combList()
    {
        Iterator iter = theHand.iterator();
        card prevCard = null;
        List subList = new ArrayList();
        while(iter.hasNext()) 
        {
            card currentCard = (card)iter.next();
            if(prevCard != null && currentCard.value == prevCard.value)
            {
                subList.add(currentCard);
                if(!iter.hasNext())
                {
                    combList.add(subList);
                }
            } else
            {
                if(prevCard != null)
                {
                    combList.add(subList);
                }
                subList = new ArrayList();
                subList.add(currentCard);
                if(!iter.hasNext())
                {
                    combList.add(subList);
                }
            }
            prevCard = currentCard;
        }
    }

    public int maxPath()
    {
        int a = pairs.size() + triples.size() + fourOfAKind.size() + threeStraight.size() + fourStraight.size() + fiveStraight.size() + sixStraight.size() + sevenStraight.size() + eightStraight.size() + nineStraight.size() + tenStraight.size() + elevenStraight.size() + twelveStraight.size() + freeSingles().size();
        return a;
    }

    private void getStraight(int size, List saveTo)
    {
        for(int i = 0; i <= combList.size() - size; i++)
        {
            List temp = new ArrayList();
            for(int j = i; j < i + size; j++)
            {
                temp.add(((List)combList.get(j)).get(0));
            }

            if(isStraight(temp))
            {
                List l = new ArrayList();
                for(int j = i; j < i + size; j++)
                {
                    l.add(combList.get(j));
                }

                saveTo.add(l);
            }
        }

    }

    public boolean hasThree()
    {
        card tos = (card)theHand.get(0);
        return tos.value == 0 && tos.suit == "Spades";
    }

    private boolean isStraight(List s)
    {
        Iterator iter = s.iterator();
        card c;
        for(card prev = (card)iter.next(); iter.hasNext(); prev = c)
        {
            c = (card)iter.next();
            if(prev.value + 1 != c.value || c.value == 12)
            {
                return false;
            }
        }

        return true;
    }

    private void getPairs()
    {
        for(int i = 0; i < theHand.size(); i++)
        {
            for(int j = 0; j < theHand.size() - 1; j++)
            {
                card tempCard = (card)theHand.get(j);
                card tempCard2 = (card)theHand.get(j + 1);
                if(tempCard.value == i && tempCard2.value == i)
                {
                    List l = new ArrayList();
                    l.add(tempCard);
                    l.add(tempCard2);
                    pairs.add(l);
                }
                if(j < theHand.size() - 2)
                {
                    card tempCard3 = (card)theHand.get(j + 2);
                    if(tempCard.value == i && tempCard3.value == i)
                    {
                        List l = new ArrayList();
                        l.add(tempCard);
                        l.add(tempCard3);
                        pairs.add(l);
                    }
                }
                if(j < theHand.size() - 3)
                {
                    card tempCard4 = (card)theHand.get(j + 3);
                    if(tempCard.value == i && tempCard4.value == i)
                    {
                        List l = new ArrayList();
                        l.add(tempCard);
                        l.add(tempCard4);
                        pairs.add(l);
                    }
                }
            }

        }

    }

    public void printPairs()
    {
        card p1;
        card p2;
        for(Iterator iter = pairs.iterator(); iter.hasNext(); System.out.println("pair:" + p1.value + " of " + p1.suit + " and " + p2.value + " of " + p2.suit))
        {
            List l = (List)iter.next();
            p1 = (card)l.get(0);
            p2 = (card)l.get(1);
        }

    }

    private void getTriples()
    {
        for(int i = 0; i < theHand.size(); i++)
        {
            for(int j = 0; j < theHand.size() - 2; j++)
            {
                card tempCard = (card)theHand.get(j);
                card tempCard2 = (card)theHand.get(j + 1);
                card tempCard3 = (card)theHand.get(j + 2);
                if(tempCard.value == i && tempCard2.value == i && tempCard3.value == i)
                {
                    List l = new ArrayList();
                    l.add(tempCard);
                    l.add(tempCard2);
                    l.add(tempCard3);
                    triples.add(l);
                }
                if(j < theHand.size() - 3)
                {
                    card tempCard4 = (card)theHand.get(j + 3);
                    if(tempCard.value == i && tempCard2.value == i && tempCard4.value == i)
                    {
                        List l = new ArrayList();
                        l.add(tempCard);
                        l.add(tempCard2);
                        l.add(tempCard4);
                        triples.add(l);
                    }
                }
            }

        }

    }

    public void printTriples()
    {
        card p1;
        card p2;
        card p3;
        for(Iterator iter = triples.iterator(); iter.hasNext(); System.out.println("triple: {" + p1.value + " of " + p1.suit + ", " + p2.value + " of " + p2.suit + " and " + p3.value + " of " + p3.suit + "}"))
        {
            List l = (List)iter.next();
            p1 = (card)l.get(0);
            p2 = (card)l.get(1);
            p3 = (card)l.get(2);
        }

    }

    private void getFourKind()
    {
        for(int i = 0; i < theHand.size(); i++)
        {
            for(int j = 0; j < theHand.size() - 3; j++)
            {
                card tempCard = (card)theHand.get(j);
                card tempCard2 = (card)theHand.get(j + 1);
                card tempCard3 = (card)theHand.get(j + 2);
                card tempCard4 = (card)theHand.get(j + 3);
                if(tempCard.value == i && tempCard2.value == i && tempCard3.value == i && tempCard4.value == i)
                {
                    List l = new ArrayList();
                    l.add(tempCard);
                    l.add(tempCard2);
                    l.add(tempCard3);
                    l.add(tempCard4);
                    fourOfAKind.add(l);
                }
            }

        }

    }

    public void printFour()
    {
        card p1;
        card p2;
        card p3;
        card p4;
        for(Iterator iter = fourOfAKind.iterator(); iter.hasNext(); System.out.println("four-of-a-kind: {" + p1.value + " of " + p1.suit + ", " + p2.value + " of " + p2.suit + ", " + p3.value + " of " + p3.suit + " and " + p4.value + " of " + p4.suit + "}"))
        {
            List l = (List)iter.next();
            p1 = (card)l.get(0);
            p2 = (card)l.get(1);
            p3 = (card)l.get(2);
            p4 = (card)l.get(3);
        }

    }

    public void printAllHands()
    {
        System.out.println("Singles        : " + theHand);
        System.out.println("Pair(s)        : " + pairs);
        System.out.println("3-of-a-Kind(s) : " + triples);
        System.out.println("4-of-a-Kind(s) : " + fourOfAKind);
        System.out.println("03-Straight(s) : " + threeStraight);
        System.out.println("04-Straight(s) : " + fourStraight);
        System.out.println("05-Straight(s) : " + fiveStraight);
        System.out.println("06-Straight(s) : " + sixStraight);
        System.out.println("07-Straight(s) : " + sevenStraight);
        System.out.println("08-Straight(s) : " + eightStraight);
        System.out.println("09-Straight(s) : " + nineStraight);
        System.out.println("10-Straight(s) : " + tenStraight);
        System.out.println("11-Straight(s) : " + elevenStraight);
        System.out.println("12-Straight(s) : " + twelveStraight);
        System.out.println("13-Straight(s) : " + thirteenStraight);
    }

    public List freeSingles()
    {
        List freeSingles = new ArrayList();
        for(Iterator iter = theHand.iterator(); iter.hasNext();)
        {
            card curCard = (card)iter.next();
            if(!inKind(curCard) && !inStraight(curCard))
            {
                freeSingles.add(curCard);
            }
        }

        return freeSingles;
    }

    private boolean inKind(card c)
    {
        for(Iterator iter = pairs.iterator(); iter.hasNext();)
        {
            List l = (List)iter.next();
            if(l.contains(c))
            {
                return true;
            }
        }

        return false;
    }

    public List straightExtra()
    {
        List l = new ArrayList();
        for(Iterator iter = theHand.iterator(); iter.hasNext();)
        {
            card c = (card)iter.next();
            if(inStraight(c) && exclusivePair(c))
            {
                l.add(c);
            }
        }

        return l;
    }

    public List findBomb()
    {
        Iterator iter = threeStraight.iterator();
        List fb = new ArrayList();
        while(iter.hasNext()) 
        {
            List l = (List)iter.next();
            if(inKind((card)((List)l.get(0)).get(0)) && inKind((card)((List)l.get(1)).get(0)) && inKind((card)((List)l.get(2)).get(0)))
            {
                List fb2 = new ArrayList();
                fb2.add(l.get(0));
                fb2.add(l.get(1));
                fb2.add(l.get(2));
                fb.add(fb2);
            }
        }
        return fb;
    }

    private boolean exclusivePair(card c)
    {
        int count = 0;
        int value = c.value;
        for(Iterator iter = theHand.iterator(); iter.hasNext();)
        {
            card tempCard = (card)iter.next();
            if(tempCard.value == value)
            {
                count++;
            }
        }

        return count == 2;
    }

    private boolean inStraight(card c)
    {
        for(Iterator iter0 = threeStraight.iterator(); iter0.hasNext();)
        {
            for(Iterator iter1 = ((List)iter0.next()).iterator(); iter1.hasNext();)
            {
                List l = (List)iter1.next();
                if(l.contains(c))
                {
                    return true;
                }
            }

        }

        return false;
    }

    public List maximalStraightSet()
    {
        if(threeStraight.isEmpty())
        {
            return threeStraight;
        }
        List usedcards = new ArrayList();
        List l = new ArrayList();
        int i;
        for(i = listOfStraights.size() - 1; ((List)listOfStraights.get(i)).isEmpty(); i--) { }
        List temp = (List)listOfStraights.get(i);
        l.addAll(temp);
        for(Iterator iter = temp.iterator(); iter.hasNext();)
        {
            List cardsInStraight = (List)iter.next();
            for(Iterator iter2 = cardsInStraight.iterator(); iter2.hasNext(); usedcards.addAll((List)iter2.next())) { }
        }

        for(i--; i >= 0; i--)
        {
            temp = (List)listOfStraights.get(i);
            List usedcards2;
            for(Iterator iter = temp.iterator(); iter.hasNext(); usedcards.addAll(usedcards2))
            {
                List cardsInStraight = (List)iter.next();
                Iterator iter2 = usedcards.iterator();
                usedcards2 = new ArrayList();
                while(iter2.hasNext()) 
                {
                    Iterator iter4 = cardsInStraight.iterator();
                    boolean out = false;
                    card c = (card)iter2.next();
                    while(iter4.hasNext()) 
                    {
                        List ifourL = (List)iter4.next();
                        if(ifourL.contains(c))
                        {
                            out = true;
                        }
                    }
                    if(out)
                    {
                        break;
                    }
                    if(!iter2.hasNext())
                    {
                        l.add(cardsInStraight);
                        for(Iterator iter3 = cardsInStraight.iterator(); iter3.hasNext(); usedcards2.addAll((List)iter3.next())) { }
                    }
                }
            }

        }

        return l;
    }

    public List danglingSingles()
    {
        List n = new ArrayList();
        List l = maximalStraightSet();
        for(Iterator iter = l.iterator(); iter.hasNext();)
        {
            List temp0 = (List)iter.next();
            if(temp0.size() > 3)
            {
                List temp1 = (List)temp0.get(0);
                if(temp1.size() == 1)
                {
                    n.add(temp1.get(0));
                }
                temp1 = (List)temp0.get(temp0.size() - 1);
                if(temp1.size() == 1)
                {
                    n.add(temp1.get(0));
                }
            }
        }

        return n;
    }
}
